part of 'page.dart';

class _SpacedRepetitionPageView extends StatelessWidget with ScreenUtilMixin {
  const _SpacedRepetitionPageView({
    required _SpacedRepetitionPageWloc wloc,
  }) : _wloc = wloc;

  final _SpacedRepetitionPageWloc _wloc;

  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// UnspecifiedLexicalItemObscureCard
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // <editor-fold defaultstate="collapsed">

  Widget _buildUnspecifiedLexicalItemObscureCardNavigationBarTitle({
    required BuildContext context,
  }) {
    return NavigationBarTitle(
      title: SpacedRepetitionPageTranslation.of(context).unspecifiedLexicalItemCardTitle,
    );
  }

  Widget _buildUnspecifiedLexicalItemObscureCardNavigationBarTrailing({
    required BuildContext context,
  }) {
    return const SizedBox();
  }

  Widget _buildCurrentUnspecifiedLexicalItemObscureCard({
    required _SpacedRepetitionPageWlocState state,
    required BuildContext context,
  }) {
    final currentCardInfo = state.currentCardInfo as UnspecifiedLexicalItemObscureCardInfo;

    return FadeBuiltTransition(
      key: ValueKey(currentCardInfo.cardId),
      opacity: _wloc.crossFadeOutAnimation,
      child: FadeBuiltTransition(
        opacity: _wloc.disappearanceFadeOutAnimation,
        child: _buildCard(
          cardInfo: currentCardInfo,
          dialect: state.dialect,
          autoPronunciationEnabled: state.autoPronunciationEnabled,
        ),
      ),
    );
  }

  Widget _buildNextUnspecifiedLexicalItemObscureCard({
    required _SpacedRepetitionPageWlocState state,
    required AnimationController cardChangeAnimationController,
    required BuildContext context,
  }) {
    final currentCardInfo = state.currentCardInfo;
    final nextCardInfo = state.nextCardInfo as UnspecifiedLexicalItemObscureCardInfo;

    final nextCard = _buildCard(
      cardInfo: nextCardInfo,
      dialect: state.dialect,
      autoPronunciationEnabled: state.autoPronunciationEnabled,
    );

    switch (currentCardInfo) {
      case UnspecifiedLexicalItemObscureCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case UnspecifiedLexicalItemExposedCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case RepetitionAnswerSelectionObscureCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case RepetitionAnswerSelectionExposedCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case RepetitionAnswerTypingCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case MemorizationCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case DailyLimitCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case LearningFinishCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );
    }
  }

  // </editor-fold>

  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// UnspecifiedLexicalItemExposedCard
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // <editor-fold defaultstate="collapsed">

  Widget _buildUnspecifiedLexicalItemExposedCardNavigationBarTitle({
    required BuildContext context,
  }) {
    return NavigationBarTitle(
      title: SpacedRepetitionPageTranslation.of(context).unspecifiedLexicalItemCardTitle,
    );
  }

  Widget _buildUnspecifiedLexicalItemExposedCardNavigationBarTrailing({
    required BuildContext context,
  }) {
    return const SizedBox();
  }

  Widget _buildCurrentUnspecifiedLexicalItemExposedCard({
    required _SpacedRepetitionPageWlocState state,
    required BuildContext context,
  }) {
    final currentCardInfo = state.currentCardInfo as UnspecifiedLexicalItemExposedCardInfo;

    return _ClockwiseSlideBuiltTransition(
      key: ValueKey(currentCardInfo.cardId),
      animation: _wloc.clockwiseSlideAnimation,
      child: _CounterclockwiseSlideBuiltTransition(
        animation: _wloc.counterclockwiseSlideAnimation,
        child: FadeBuiltTransition(
          opacity: _wloc.disappearanceFadeOutAnimation,
          child: _buildCard(
            cardInfo: currentCardInfo,
            dialect: state.dialect,
            autoPronunciationEnabled: state.autoPronunciationEnabled,
          ),
        ),
      ),
    );
  }

  Widget _buildNextUnspecifiedLexicalItemExposedCard({
    required _SpacedRepetitionPageWlocState state,
    required AnimationController cardChangeAnimationController,
    required BuildContext context,
  }) {
    final currentCardInfo = state.currentCardInfo;
    final nextCardInfo = state.nextCardInfo as UnspecifiedLexicalItemExposedCardInfo;

    final nextCard = _buildCard(
      cardInfo: nextCardInfo,
      dialect: state.dialect,
      autoPronunciationEnabled: state.autoPronunciationEnabled,
    );

    if (currentCardInfo is UnspecifiedLexicalItemObscureCardInfo &&
        currentCardInfo.finishEvent.isExposed) {
      final fadeAnimation = cardChangeAnimationController.drive(_wloc.easeOutTween);

      return Stack(
        key: ValueKey(nextCardInfo.cardId),
        children: [
          _buildEmptyCard(
            context: context,
          ),
          FadeBuiltTransition(
            opacity: fadeAnimation,
            child: nextCard,
          ),
        ],
      );
    }

    throw UnimplementedError();
  }

  // </editor-fold>

  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// RepetitionAnswerSelectionObscureCard
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // <editor-fold defaultstate="collapsed">

  Widget _buildRepetitionAnswerSelectionObscureCardNavigationBarTitle({
    required RepetitionAnswerSelectionObscureCardInfo cardInfo,
    required BuildContext context,
  }) {
    return NavigationBarTitle(
      title: SpacedRepetitionPageTranslation.of(context).buildRepetitionCardTitle(
        repeatableLexicalItemCount: cardInfo.repeatableLexicalItemCount,
      ),
    );
  }

  Widget _buildRepetitionAnswerSelectionObscureCardNavigationBarTrailing({
    required BuildContext context,
  }) {
    const keyboardIconSize = 27.0;
    final buttonWidth = keyboardIconSize * kSemiboldIconRatio +
        kVisibleNavigationBarHorizontalIconPadding * logWidthScaleFactor * 2;

    return AppIconButton(
      height: double.infinity,
      width: buttonWidth,
      icon: Icon(
        CustomSemiboldIcons.keyboard,
        color: CoreTheme.of(context).primaryColor,
        size: keyboardIconSize,
      ),
      onPressed: _wloc.onRepetitionAnswerSelectionObscureCardTypingModeEnablementButtonPressed,
    );
  }

  Widget _buildCurrentRepetitionAnswerSelectionObscureCard({
    required _SpacedRepetitionPageWlocState state,
    required BuildContext context,
  }) {
    final currentCardInfo = state.currentCardInfo as RepetitionAnswerSelectionObscureCardInfo;

    return FadeBuiltTransition(
      key: ValueKey(currentCardInfo.cardId),
      opacity: _wloc.crossFadeOutAnimation,
      child: FadeBuiltTransition(
        opacity: _wloc.disappearanceFadeOutAnimation,
        child: _buildCard(
          cardInfo: currentCardInfo,
          dialect: state.dialect,
          autoPronunciationEnabled: state.autoPronunciationEnabled,
        ),
      ),
    );
  }

  Widget _buildNextRepetitionAnswerSelectionObscureCard({
    required _SpacedRepetitionPageWlocState state,
    required AnimationController cardChangeAnimationController,
    required BuildContext context,
  }) {
    final currentCardInfo = state.currentCardInfo;
    final nextCardInfo = state.nextCardInfo as RepetitionAnswerSelectionObscureCardInfo;

    final nextCard = _buildCard(
      cardInfo: nextCardInfo,
      dialect: state.dialect,
      autoPronunciationEnabled: state.autoPronunciationEnabled,
    );

    switch (currentCardInfo) {
      case UnspecifiedLexicalItemObscureCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case UnspecifiedLexicalItemExposedCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case RepetitionAnswerSelectionObscureCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case RepetitionAnswerSelectionExposedCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case RepetitionAnswerTypingCardInfo():
        if (currentCardInfo.finishEvent.isTypingModeDisabled) {
          final fadeAnimation = cardChangeAnimationController.drive(_wloc.easeOutTween);

          return Stack(
            key: ValueKey(nextCardInfo.cardId),
            children: [
              _buildEmptyCard(
                context: context,
              ),
              FadeBuiltTransition(
                opacity: fadeAnimation,
                child: nextCard,
              ),
            ],
          );
        }

        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case MemorizationCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case DailyLimitCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case LearningFinishCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );
    }
  }

  // </editor-fold>

  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// RepetitionAnswerSelectionExposedCard
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // <editor-fold defaultstate="collapsed">

  Widget _buildRepetitionAnswerSelectionExposedCardNavigationBarTitle({
    required RepetitionAnswerSelectionExposedCardInfo cardInfo,
    required BuildContext context,
  }) {
    return NavigationBarTitle(
      title: SpacedRepetitionPageTranslation.of(context).buildRepetitionCardTitle(
        repeatableLexicalItemCount: cardInfo.repeatableLexicalItemCount,
      ),
    );
  }

  Widget _buildRepetitionAnswerSelectionExposedCardNavigationBarTrailing({
    required BuildContext context,
  }) {
    return const SizedBox();
  }

  Widget _buildCurrentRepetitionAnswerSelectionExposedCard({
    required _SpacedRepetitionPageWlocState state,
    required BuildContext context,
  }) {
    final currentCardInfo = state.currentCardInfo as RepetitionAnswerSelectionExposedCardInfo;

    return _ClockwiseSlideBuiltTransition(
      key: ValueKey(currentCardInfo.cardId),
      animation: _wloc.clockwiseSlideAnimation,
      child: _CounterclockwiseSlideBuiltTransition(
        animation: _wloc.counterclockwiseSlideAnimation,
        child: FadeBuiltTransition(
          opacity: _wloc.disappearanceFadeOutAnimation,
          child: _buildCard(
            cardInfo: currentCardInfo,
            dialect: state.dialect,
            autoPronunciationEnabled: state.autoPronunciationEnabled,
          ),
        ),
      ),
    );
  }

  Widget _buildNextRepetitionAnswerSelectionExposedCard({
    required _SpacedRepetitionPageWlocState state,
    required AnimationController cardChangeAnimationController,
    required BuildContext context,
  }) {
    final currentCardInfo = state.currentCardInfo;
    final nextCardInfo = state.nextCardInfo as RepetitionAnswerSelectionExposedCardInfo;

    final nextCard = _buildCard(
      cardInfo: nextCardInfo,
      dialect: state.dialect,
      autoPronunciationEnabled: state.autoPronunciationEnabled,
    );

    if (currentCardInfo is RepetitionAnswerSelectionObscureCardInfo &&
        currentCardInfo.finishEvent.isExposed) {
      final fadeAnimation = cardChangeAnimationController.drive(_wloc.easeOutTween);

      return Stack(
        key: ValueKey(nextCardInfo.cardId),
        children: [
          _buildEmptyCard(
            context: context,
          ),
          FadeBuiltTransition(
            opacity: fadeAnimation,
            child: nextCard,
          ),
        ],
      );
    }

    if (currentCardInfo is RepetitionAnswerTypingCardInfo &&
        currentCardInfo.finishEvent.isExplicitMarkRequired) {
      final fadeAnimation = cardChangeAnimationController.drive(_wloc.easeOutTween);

      return Stack(
        key: ValueKey(nextCardInfo.cardId),
        children: [
          _buildEmptyCard(
            context: context,
          ),
          FadeBuiltTransition(
            opacity: fadeAnimation,
            child: nextCard,
          ),
        ],
      );
    }

    throw UnimplementedError();
  }

  // </editor-fold>

  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// RepetitionAnswerTypingCard
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // <editor-fold defaultstate="collapsed">

  Widget _buildRepetitionAnswerTypingCardNavigationBarTitle({
    required RepetitionAnswerTypingCardInfo cardInfo,
    required BuildContext context,
  }) {
    return NavigationBarTitle(
      title: SpacedRepetitionPageTranslation.of(context).buildRepetitionCardTitle(
        repeatableLexicalItemCount: cardInfo.repeatableLexicalItemCount,
      ),
    );
  }

  Widget _buildRepetitionAnswerTypingCardNavigationBarTrailing({
    required BuildContext context,
  }) {
    const kKeyboardIconSize = 27.0;
    final buttonWidth = kKeyboardIconSize * kSemiboldIconRatio +
        kVisibleNavigationBarHorizontalIconPadding * logWidthScaleFactor * 2;

    return AppIconButton(
      height: double.infinity,
      width: buttonWidth,
      icon: Icon(
        CustomSemiboldIcons.keyboard_close,
        color: CoreTheme.of(context).primaryColor,
        size: kKeyboardIconSize,
      ),
      onPressed: _wloc.onRepetitionAnswerTypingCardTypingModeDisablementButtonPressed,
    );
  }

  Widget _buildCurrentRepetitionAnswerTypingCard({
    required _SpacedRepetitionPageWlocState state,
    required BuildContext context,
  }) {
    final currentCardInfo = state.currentCardInfo as RepetitionAnswerTypingCardInfo;

    return SlideBuiltTransition(
      key: ValueKey(currentCardInfo.cardId),
      position: _wloc.leftSlideOutAnimation,
      child: FadeBuiltTransition(
        opacity: _wloc.crossFadeOutAnimation,
        child: FadeBuiltTransition(
          opacity: _wloc.disappearanceFadeOutAnimation,
          child: _buildCard(
            cardInfo: currentCardInfo,
            dialect: state.dialect,
            autoPronunciationEnabled: state.autoPronunciationEnabled,
            focusNode: _wloc.currentTypingCardFocusNode!,
          ),
        ),
      ),
    );
  }

  Widget _buildNextRepetitionAnswerTypingCard({
    required _SpacedRepetitionPageWlocState state,
    required AnimationController cardChangeAnimationController,
    required BuildContext context,
  }) {
    final currentCardInfo = state.currentCardInfo;
    final nextCardInfo = state.nextCardInfo as RepetitionAnswerTypingCardInfo;

    final nextCard = _buildCard(
      cardInfo: nextCardInfo,
      dialect: state.dialect,
      autoPronunciationEnabled: state.autoPronunciationEnabled,
      focusNode: _wloc.nextTypingCardFocusNode!,
    );

    switch (currentCardInfo) {
      case UnspecifiedLexicalItemObscureCardInfo():
        return nextCard;

      case UnspecifiedLexicalItemExposedCardInfo():
        return nextCard;

      case RepetitionAnswerSelectionObscureCardInfo():
        final fadeAnimation = cardChangeAnimationController.drive(_wloc.easeOutTween);

        return Container(
          key: ValueKey(nextCardInfo.cardId),
          color: HomeCoreTheme.of(context).cardColor,
          child: FadeBuiltTransition(
            opacity: fadeAnimation,
            child: nextCard,
          ),
        );

      case RepetitionAnswerSelectionExposedCardInfo():
        return nextCard;

      case RepetitionAnswerTypingCardInfo():
        if (currentCardInfo.finishEvent.isVanished) {
          return nextCard;
        }

        final slideAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.leftSlideInTween);

        return SlideBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          position: slideAnimation,
          child: nextCard,
        );

      case DailyLimitCardInfo():
        return nextCard;

      case MemorizationCardInfo():
        return nextCard;

      case LearningFinishCardInfo():
        return nextCard;
    }
  }

  // </editor-fold>

  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// MemorizationCard
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // <editor-fold defaultstate="collapsed">

  Widget _buildMemorizationCardNavigationBarTitle({
    required BuildContext context,
  }) {
    return NavigationBarTitle(
      title: HomeCoreTranslation.of(context).memorizationCardInstruction,
    );
  }

  Widget _buildMemorizationCardNavigationBarTrailing({
    required BuildContext context,
  }) {
    return const SizedBox();
  }

  Widget _buildCurrentMemorizationCard({
    required _SpacedRepetitionPageWlocState state,
    required BuildContext context,
  }) {
    final currentCardInfo = state.currentCardInfo as MemorizationCardInfo;

    return _ClockwiseSlideBuiltTransition(
      key: ValueKey(currentCardInfo.cardId),
      animation: _wloc.clockwiseSlideAnimation,
      child: FadeBuiltTransition(
        opacity: _wloc.disappearanceFadeOutAnimation,
        child: _buildCard(
          cardInfo: currentCardInfo,
          dialect: state.dialect,
          autoPronunciationEnabled: state.autoPronunciationEnabled,
        ),
      ),
    );
  }

  Widget _buildNextMemorizationCard({
    required _SpacedRepetitionPageWlocState state,
    required AnimationController cardChangeAnimationController,
    required BuildContext context,
  }) {
    final currentCardInfo = state.currentCardInfo;
    final nextCardInfo = state.nextCardInfo as MemorizationCardInfo;

    final nextCard = _buildCard(
      cardInfo: nextCardInfo,
      dialect: state.dialect,
      autoPronunciationEnabled: state.autoPronunciationEnabled,
    );

    if (currentCardInfo is RepetitionAnswerTypingCardInfo &&
        currentCardInfo.finishEvent.isMarkedAsUnremembered) {
      final fadeAnimation = cardChangeAnimationController.drive(_wloc.easeOutTween);

      return Stack(
        key: ValueKey(nextCardInfo.cardId),
        children: [
          _buildEmptyCard(
            context: context,
          ),
          FadeBuiltTransition(
            opacity: fadeAnimation,
            child: nextCard,
          ),
        ],
      );
    }

    throw UnimplementedError();
  }

  // </editor-fold>

  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// DailyLimitCard
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // <editor-fold defaultstate="collapsed">

  Widget _buildDailyLimitCardNavigationBarTitle({
    required BuildContext context,
  }) {
    return NavigationBarTitle(
      title: SpacedRepetitionPageTranslation.of(context).dailyLimitCardTitle,
    );
  }

  Widget _buildDailyLimitCardNavigationBarTrailing({
    required BuildContext context,
  }) {
    return const SizedBox();
  }

  Widget _buildCurrentDailyLimitCard({
    required _SpacedRepetitionPageWlocState state,
    required BuildContext context,
  }) {
    final currentCardInfo = state.currentCardInfo as DailyLimitCardInfo;

    return FadeBuiltTransition(
      opacity: _wloc.disappearanceFadeOutAnimation,
      child: _buildCard(
        cardInfo: currentCardInfo,
        dialect: state.dialect,
        autoPronunciationEnabled: state.autoPronunciationEnabled,
      ),
    );
  }

  Widget _buildNextDailyLimitCard({
    required _SpacedRepetitionPageWlocState state,
    required AnimationController cardChangeAnimationController,
    required BuildContext context,
  }) {
    final currentCardInfo = state.currentCardInfo;
    final nextCardInfo = state.nextCardInfo as DailyLimitCardInfo;

    final nextCard = _buildCard(
      cardInfo: nextCardInfo,
      dialect: state.dialect,
      autoPronunciationEnabled: state.autoPronunciationEnabled,
    );

    switch (currentCardInfo) {
      case UnspecifiedLexicalItemObscureCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case UnspecifiedLexicalItemExposedCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case RepetitionAnswerSelectionObscureCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case RepetitionAnswerSelectionExposedCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case RepetitionAnswerTypingCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case MemorizationCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case LearningFinishCardInfo():
        final scaleAnimation =
            cardChangeAnimationController.drive(_wloc.easeOutTween).drive(_wloc.nextCardScaleTween);

        return ScaleBuiltTransition(
          key: ValueKey(nextCardInfo.cardId),
          scale: scaleAnimation,
          child: nextCard,
        );

      case DailyLimitCardInfo():
        throw UnimplementedError();
    }
  }

  // </editor-fold>

  /////////////////////////////////////////////////////////////////////////////////////////////////
  /// LearningFinishCard
  /////////////////////////////////////////////////////////////////////////////////////////////////
  // <editor-fold defaultstate="collapsed">

  Widget _buildLearningFinishCardNavigationBarTitle({
    required BuildContext context,
  }) {
    return NavigationBarTitle(
      title: SpacedRepetitionPageTranslation.of(context).learningFinishCardTitle,
    );
  }

  Widget _buildLearningFinishCardNavigationBarTrailing({
    required BuildContext context,
  }) {
    return const SizedBox();
  }

  Widget _buildCurrentLearningFinishCard({
    required _SpacedRepetitionPageWlocState state,
    required BuildContext context,
  }) {
    final currentCardInfo = state.currentCardInfo as LearningFinishCardInfo;

    return FadeBuiltTransition(
      opacity: _wloc.disappearanceFadeOutAnimation,
      child: _buildCard(
        cardInfo: currentCardInfo,
        dialect: state.dialect,
        autoPronunciationEnabled: state.autoPronunciationEnabled,
      ),
    );
  }

  Widget _buildNextLearningFinishCard({
    required _SpacedRepetitionPageWlocState state,
    required AnimationController cardChangeAnimationController,
    required BuildContext context,
  }) {
    final nextCardInfo = state.nextCardInfo as LearningFinishCardInfo;

    return _buildCard(
      cardInfo: nextCardInfo,
      dialect: state.dialect,
      autoPronunciationEnabled: state.autoPronunciationEnabled,
    );
  }

  // </editor-fold>

  Widget _buildNavigationBarTitle({
    required _SpacedRepetitionPageWlocState state,
    required AnimationController? cardChangeAnimationController,
    required BuildContext context,
  }) {
    if (cardChangeAnimationController == null) {
      return _buildNavigationBarTitleByCardInfo(
        cardInfo: state.currentCardInfo,
        context: context,
      );
    }

    return AnimatedBuilder(
      animation: cardChangeAnimationController,
      builder: (context, _) {
        final cardInfo = switch (cardChangeAnimationController.value) {
          < 0.5 => state.currentCardInfo,
          _ => state.nextCardInfo!,
        };

        return _buildNavigationBarTitleByCardInfo(
          cardInfo: cardInfo,
          context: context,
        );
      },
    );
  }

  Widget _buildNavigationBarTitleByCardInfo({
    required CardInfo cardInfo,
    required BuildContext context,
  }) {
    return switch (cardInfo) {
      UnspecifiedLexicalItemObscureCardInfo() =>
        _buildUnspecifiedLexicalItemObscureCardNavigationBarTitle(
        context: context,
      ),
      UnspecifiedLexicalItemExposedCardInfo() =>
        _buildUnspecifiedLexicalItemExposedCardNavigationBarTitle(
        context: context,
      ),
      RepetitionAnswerSelectionObscureCardInfo() =>
        _buildRepetitionAnswerSelectionObscureCardNavigationBarTitle(
        cardInfo: cardInfo,
        context: context,
      ),
      RepetitionAnswerSelectionExposedCardInfo() =>
        _buildRepetitionAnswerSelectionExposedCardNavigationBarTitle(
        cardInfo: cardInfo,
        context: context,
      ),
      RepetitionAnswerTypingCardInfo() => _buildRepetitionAnswerTypingCardNavigationBarTitle(
        cardInfo: cardInfo,
        context: context,
      ),
      MemorizationCardInfo() => _buildMemorizationCardNavigationBarTitle(
        context: context,
      ),
      DailyLimitCardInfo() => _buildDailyLimitCardNavigationBarTitle(
        context: context,
      ),
      LearningFinishCardInfo() => _buildLearningFinishCardNavigationBarTitle(
        context: context,
      ),
    };
  }

  Widget _buildNavigationBarTrailing({
    required _SpacedRepetitionPageWlocState state,
    required AnimationController? cardChangeAnimationController,
    required BuildContext context,
  }) {
    if (cardChangeAnimationController == null) {
      return _buildNavigationBarTrailingByCardInfo(
        cardInfo: state.currentCardInfo,
        context: context,
      );
    }

    return AnimatedBuilder(
      animation: cardChangeAnimationController,
      builder: (context, _) {
        final CardInfo cardInfo;

        if (cardChangeAnimationController.value < 0.5) {
          cardInfo = state.currentCardInfo;
        } else {
          cardInfo = state.nextCardInfo!;
        }

        return _buildNavigationBarTrailingByCardInfo(
          cardInfo: cardInfo,
          context: context,
        );
      },
    );
  }

  Widget _buildNavigationBarTrailingByCardInfo({
    required CardInfo cardInfo,
    required BuildContext context,
  }) {
    return switch (cardInfo) {
      UnspecifiedLexicalItemObscureCardInfo() =>
        _buildUnspecifiedLexicalItemObscureCardNavigationBarTrailing(
        context: context,
      ),
      UnspecifiedLexicalItemExposedCardInfo() =>
        _buildUnspecifiedLexicalItemExposedCardNavigationBarTrailing(
        context: context,
      ),
      RepetitionAnswerSelectionObscureCardInfo() =>
        _buildRepetitionAnswerSelectionObscureCardNavigationBarTrailing(
        context: context,
      ),
      RepetitionAnswerSelectionExposedCardInfo() =>
        _buildRepetitionAnswerSelectionExposedCardNavigationBarTrailing(
        context: context,
      ),
      RepetitionAnswerTypingCardInfo() => _buildRepetitionAnswerTypingCardNavigationBarTrailing(
        context: context,
      ),
      MemorizationCardInfo() => _buildMemorizationCardNavigationBarTrailing(
        context: context,
      ),
      DailyLimitCardInfo() => _buildDailyLimitCardNavigationBarTrailing(
        context: context,
      ),
      LearningFinishCardInfo() => _buildLearningFinishCardNavigationBarTrailing(
        context: context,
      ),
    };
  }

  Widget _buildCurrentCard({
    required _SpacedRepetitionPageWlocState state,
    required BuildContext context,
  }) {
    final currentCardInfo = state.currentCardInfo;
    switch (currentCardInfo) {
      case UnspecifiedLexicalItemObscureCardInfo():
        return Column(
          children: [
            _buildDummyProgressBar(
              state: state,
              context: context,
            ),
            Expanded(
              child: _buildCurrentUnspecifiedLexicalItemObscureCard(
                state: state,
                context: context,
              ),
            ),
          ],
        );

      case UnspecifiedLexicalItemExposedCardInfo():
        return Column(
          children: [
            _buildDummyProgressBar(
              state: state,
              context: context,
            ),
            Expanded(
              child: _buildCurrentUnspecifiedLexicalItemExposedCard(
                state: state,
                context: context,
              ),
            ),
          ],
        );

      case RepetitionAnswerSelectionObscureCardInfo():
        return Column(
          children: [
            _buildDummyProgressBar(
              state: state,
              context: context,
            ),
            Expanded(
              child: _buildCurrentRepetitionAnswerSelectionObscureCard(
                state: state,
                context: context,
              ),
            ),
          ],
        );

      case RepetitionAnswerSelectionExposedCardInfo():
        return Column(
          children: [
            _buildDummyProgressBar(
              state: state,
              context: context,
            ),
            Expanded(
              child: _buildCurrentRepetitionAnswerSelectionExposedCard(
                state: state,
                context: context,
              ),
            ),
          ],
        );

      case RepetitionAnswerTypingCardInfo():
        return _buildCurrentRepetitionAnswerTypingCard(
          state: state,
          context: context,
        );

      case MemorizationCardInfo():
        return Column(
          children: [
            _buildDummyProgressBar(
              state: state,
              context: context,
            ),
            Expanded(
              child: _buildCurrentMemorizationCard(
                state: state,
                context: context,
              ),
            ),
          ],
        );

      case DailyLimitCardInfo():
        return Column(
          children: [
            _buildDummyProgressBar(
              state: state,
              context: context,
            ),
            Expanded(
              child: _buildCurrentDailyLimitCard(
                state: state,
                context: context,
              ),
            ),
          ],
        );

      case LearningFinishCardInfo():
        return _buildCurrentLearningFinishCard(
          state: state,
          context: context,
        );
    }
  }

  Widget? _buildNextCard({
    required _SpacedRepetitionPageWlocState state,
    required AnimationController? cardChangeAnimationController,
    required BuildContext context,
  }) {
    final nextCardInfo = state.nextCardInfo;

    if (nextCardInfo == null) {
      return null;
    }

    switch (nextCardInfo) {
      case UnspecifiedLexicalItemObscureCardInfo():
        return Column(
          children: [
            _buildDummyProgressBar(
              state: state,
              context: context,
            ),
            Expanded(
              child: _buildNextUnspecifiedLexicalItemObscureCard(
                state: state,
                cardChangeAnimationController: cardChangeAnimationController!,
                context: context,
              ),
            ),
          ],
        );

      case UnspecifiedLexicalItemExposedCardInfo():
        return Column(
          children: [
            _buildDummyProgressBar(
              state: state,
              context: context,
            ),
            Expanded(
              child: _buildNextUnspecifiedLexicalItemExposedCard(
                state: state,
                cardChangeAnimationController: cardChangeAnimationController!,
                context: context,
              ),
            ),
          ],
        );

      case RepetitionAnswerSelectionObscureCardInfo():
        return Column(
          children: [
            _buildDummyProgressBar(
              state: state,
              context: context,
            ),
            Expanded(
              child: _buildNextRepetitionAnswerSelectionObscureCard(
                state: state,
                cardChangeAnimationController: cardChangeAnimationController!,
                context: context,
              ),
            ),
          ],
        );

      case RepetitionAnswerSelectionExposedCardInfo():
        return Column(
          children: [
            _buildDummyProgressBar(
              state: state,
              context: context,
            ),
            Expanded(
              child: _buildNextRepetitionAnswerSelectionExposedCard(
                state: state,
                cardChangeAnimationController: cardChangeAnimationController!,
                context: context,
              ),
            ),
          ],
        );

      case RepetitionAnswerTypingCardInfo():
        return _buildNextRepetitionAnswerTypingCard(
          state: state,
          cardChangeAnimationController: cardChangeAnimationController!,
          context: context,
        );

      case MemorizationCardInfo():
        return Column(
          children: [
            _buildDummyProgressBar(
              state: state,
              context: context,
            ),
            Expanded(
              child: _buildNextMemorizationCard(
                state: state,
                cardChangeAnimationController: cardChangeAnimationController!,
                context: context,
              ),
            ),
          ],
        );

      case DailyLimitCardInfo():
        return Column(
          children: [
            _buildDummyProgressBar(
              state: state,
              context: context,
            ),
            Expanded(
              child: _buildNextDailyLimitCard(
                state: state,
                cardChangeAnimationController: cardChangeAnimationController!,
                context: context,
              ),
            ),
          ],
        );

      case LearningFinishCardInfo():
        return _buildNextLearningFinishCard(
          state: state,
          cardChangeAnimationController: cardChangeAnimationController!,
          context: context,
        );
    }
  }

  Widget _buildCard({
    required CardInfo cardInfo,
    required Dialect dialect,
    required bool autoPronunciationEnabled,
    FocusNode? focusNode,
  }) {
    switch (cardInfo) {
      case UnspecifiedLexicalItemObscureCardInfo():
        return UnspecifiedLexicalItemObscureCard(
          key: ValueKey(cardInfo.cardId),
          lexicalItem: cardInfo.lexicalItem,
          safeToPronounce: cardInfo.safeToPronounce,
          dialect: dialect,
          onExposureButtonPressed: _wloc.onUnspecifiedLexicalItemObscureCardExposureButtonPressed,
        );

      case UnspecifiedLexicalItemExposedCardInfo():
        return UnspecifiedLexicalItemExposedCard(
          key: ValueKey(cardInfo.cardId),
          lexicalItem: cardInfo.lexicalItem,
          safeToPronounce: cardInfo.safeToPronounce,
          dialect: dialect,
          imagePath: cardInfo.imagePath,
          onMarkAsKnownButtonPressed:
              _wloc.onUnspecifiedLexicalItemExposedCardMarkAsKnownButtonPressed,
          onMarkAsUnknownButtonPressed:
              _wloc.onUnspecifiedLexicalItemExposedCardMarkAsUnknownButtonPressed,
          onMoreActionButtonPressed:
              _wloc.onUnspecifiedLexicalItemExposedCardMoreActionButtonPressed,
        );

      case RepetitionAnswerSelectionObscureCardInfo():
        return RepetitionAnswerSelectionObscureCard(
          key: ValueKey(cardInfo.cardId),
          lexicalItem: cardInfo.lexicalItem,
          onExposureButtonPressed:
              _wloc.onRepetitionAnswerSelectionObscureCardExposureButtonPressed,
        );

      case RepetitionAnswerSelectionExposedCardInfo():
        return RepetitionAnswerSelectionExposedCard(
          key: ValueKey(cardInfo.cardId),
          lexicalItem: cardInfo.lexicalItem,
          safeToPronounce: cardInfo.safeToPronounce,
          dialect: dialect,
          imagePath: cardInfo.imagePath,
          onMarkAsBadlyRememberedButtonPressed:
              _wloc.onRepetitionAnswerSelectionExposedMarkAsBadlyRememberedButtonPressed,
          onMarkAsRememberedButtonPressed:
              _wloc.onRepetitionAnswerSelectionExposedMarkAsRememberedButtonPressed,
          onMarkAsUnrememberedButtonPressed:
              _wloc.onRepetitionAnswerSelectionExposedMarkAsUnrememberedButtonPressed,
          onMoreActionButtonPressed:
              _wloc.onRepetitionAnswerSelectionExposedCardMoreActionButtonPressed,
        );

      case RepetitionAnswerTypingCardInfo():
        return RepetitionAnswerTypingCard(
          key: ValueKey(cardInfo.cardId),
          focusNode: focusNode!,
          lexicalItem: cardInfo.lexicalItem,
          onHintUsed: _wloc.onRepetitionAnswerTypingCardHintUsed,
          onAnsweredCorrectly: _wloc.onRepetitionAnswerTypingCardLexicalItemTypedCorrectly,
          onMarkAsUnrememberedButtonPressed:
              _wloc.onRepetitionAnswerTypingCardMarkAsUnrememberedButtonPressed,
        );

      case MemorizationCardInfo():
        return MemorizationCard(
          key: ValueKey(cardInfo.cardId),
          lexicalItem: cardInfo.lexicalItem,
          safeToPronounce: cardInfo.safeToPronounce,
          onContinuationButtonPressed: _wloc.onMemorizationCardClosingButtonPressed,
          dialect: dialect,
          imagePath: cardInfo.imagePath,
          onMoreActionButtonPressed: _wloc.onMemorizationCardMoreActionButtonPressed,
        );

      case DailyLimitCardInfo():
        return const DailyLimitCard();

      case LearningFinishCardInfo():
        return const LearningFinishCard();
    }
  }

  Widget _buildContent({
    required _SpacedRepetitionPageWlocState state,
    required AnimationController? cardChangeAnimationController,
    required BuildContext context,
  }) {
    return Stack(
      fit: StackFit.expand,
      children: [
        if (state.nextCardInfo != null)
          _buildNextCard(
            state: state,
            cardChangeAnimationController: cardChangeAnimationController!,
            context: context,
          )!,
        _buildCurrentCard(
          state: state,
          context: context,
        ),
      ],
    );
  }

  Widget _buildEmptyCard({
    required BuildContext context,
  }) {
    return const SafeArea(
      left: false,
      top: false,
      right: false,
      bottom: true,
      maintainBottomViewPadding: true,
      child: LexicalItemCard(
        child: SizedBox(),
      ),
    );
  }

  Widget _buildProgressBar({
    required _SpacedRepetitionPageWlocState state,
    required BuildContext context,
  }) {
    return Padding(
      padding: const EdgeInsets.fromLTRB(8, 8, 8, 0) * logWidthScaleFactor,
      child: AnimatedSegmentedProgressBar(
        duration: const Duration(milliseconds: 300),
        preferredThickness: 6.0,
        currentProgress: state.currentTrainableLexicalItemPickingProgress,
        previousProgress: state.previousTrainableLexicalItemPickingProgress,
        progressColor: CoreTheme.of(context).primaryColor,
        backgroundColor: LearningCoreTheme.of(context).segmentedProgressBarBackgroundColor,
        segmentCount: state.trainingSize,
        scaleFactor: logWidthScaleFactor,
      ),
    );
  }

  Widget _buildDummyProgressBar({
    required _SpacedRepetitionPageWlocState state,
    required BuildContext context,
  }) {
    return Visibility(
      visible: false,
      maintainSize: true,
      maintainAnimation: true,
      maintainState: true,
      child: Padding(
        padding: const EdgeInsets.fromLTRB(8, 8, 8, 0) * logWidthScaleFactor,
        child: SegmentedProgressBar(
          preferredThickness: 6.0,
          progress: 0.0,
          progressColor: const Color(0x00000000),
          backgroundColor: const Color(0x00000000),
          segmentCount: state.trainingSize,
          scaleFactor: logWidthScaleFactor,
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder(
      valueListenable: _wloc.cardChangeAnimationControllerNotifier,
      builder: (context, cardChangeAnimationController, _) {
        return IgnorePointer(
          ignoring: cardChangeAnimationController != null,
          child: WlocBuilder<_SpacedRepetitionPageWloc, _SpacedRepetitionPageWlocState>(
            wloc: _wloc,
            builder: (context, state) {
              return CupertinoPageScaffold(
                resizeToAvoidBottomInset: false,
                backgroundColor: CoreTheme.of(context).backgroundColor,
                navigationBar: CupertinoNavigationBar(
                  backgroundColor: CoreTheme.of(context).navigationBarColor,
                  brightness: CoreTheme.of(context).brightness,
                  automaticallyImplyLeading: false,
                  automaticallyImplyMiddle: false,
                  padding: EdgeInsetsDirectional.zero,
                  middle: _buildNavigationBarTitle(
                    state: state,
                    cardChangeAnimationController: cardChangeAnimationController,
                    context: context,
                  ),
                  leading: AppBackButton(
                    onPressed: Navigator.of(context).pop,
                  ),
                  trailing: _buildNavigationBarTrailing(
                    state: state,
                    cardChangeAnimationController: cardChangeAnimationController,
                    context: context,
                  ),
                ),
                child: SizedBox.expand(
                  child: Stack(
                    children: [
                      _buildContent(
                        state: state,
                        cardChangeAnimationController: cardChangeAnimationController,
                        context: context,
                      ),
                      _buildProgressBar(
                        state: state,
                        context: context,
                      ),
                    ],
                  ),
                ),
              );
            },
          ),
        );
      },
    );
  }
}
